#include "stdio.h"
#include <stdarg.h>
#include "console.h"
#include "lock.h"
#include "type.h"

#include "dbg.h"

static char digits[] = "0123456789abcdef";

spinlock_t pr_lk;
void
printinit(void) {
    spinlock_init(&pr_lk, "print");
}
static void
printint(int data, int base) {
    char result[16];
    uint32_t num;
    if (data < 0) {
        console_putc('-');
        num = -data;
    } else
        num = data;
    int count = 0;
    do {
        result[count++] = digits[num % base];
    } while ((num /= base) != 0);
    while (--count >= 0)
        console_putc(result[count]);
}

static void
printptr(address_t ptr) {
    console_putc('0');
    console_putc('x');
    for (int i = 0; i < UINT64_LEN; i++) {
        console_putc(digits[ptr >> (UINT64_LEN * 4 - 4)]);
        ptr <<= 4;
    }
}

int
putchar(int c) {
    console_putc(c);
    return c;
}

int
printf(char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    int ch;
    char* str;
    int count = 0;
    //    const char percentage = '%';
    spinlock_acquire(&pr_lk);
    for (int i = 0; (ch = fmt[i] & 0xff) != 0; i++) {
        if (ch != '%') {
            console_putc(ch);

            continue;
        }
        i++;
        ch = fmt[i] & 0xff;
        switch (ch) {
            case 'd': {
                printint(va_arg(ap, int), 10);
                count++;
                break;
            }
            case 'x': {
                printint(va_arg(ap, int), 16);
                count++;
                break;
            }
            case 's': {
                str = va_arg(ap, char*);
                for (int i = 0; str[i] != '\0'; i++) {
                    console_putc(str[i]);
                }
                count++;
                break;
            }
            case 'p': {
                printptr(va_arg(ap, address_t));
                count++;
                break;
            }
            default:
                // Print unknown % sequence to draw attention
                console_putc('%');
                console_putc(ch);
                break;
        }
    }
    spinlock_release(&pr_lk);
    return count;
}

void
panic(char* s) {
    printf("panic: %s\n", s);
    // printf(s);
    // printf("\n");
    while (1)
        ;
}